“Новая” и “старая” методики контроля отрицательных остатков при проведении документов в системе 1С:Предприятие 8.3

Эта статья предназначена для внедренцев 1С – и особенно для тех, кто готовится к Аттестации на 1С:Специалист по платформе.

Сегодня мы разберем 2 методики контроля остатков – причем не только остатков на складе, но и, например, взаиморасчетов (“какова текущая задолженность клиента и можно ли отгружать ему товары”)

Обе методики применяются и в типовых конфигурациях, и в Аттестационных заданиях. И поскольку их две – нужно четко понимать, когда применима “новая” методика, а когда только “старая”.

Это базовые знания для программистов 1С, рекомендуем не оставлять пробелов в таких областях. На изучение у Вас должно уйти 15 минут :)

Постановка задачи

Возьмем простую конфигурацию с документами “Поступление товаров” и “Реализация товаров”:

Метаданные документов модельной конфигурации

Для учета остатков используется регистр накопления “Свободные остатки”:

Метаданные регистра Свободные остатки

При проведении документа “Поступление товаров” выполняются движения-приход:

Процедура ОбработкаПроведения(Отказ, Режим)
   
    Движения.СвободныеОстатки.Записывать = Истина;
    Для Каждого ТекСтрокаТовары Из Товары Цикл
        Движение = Движения.СвободныеОстатки.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
        Движение.Период = Дата;
        Движение.Номенклатура = ТекСтрокаТовары.Номенклатура;
        Движение.Количество = ТекСтрокаТовары.Количество;
    КонецЦикла;

КонецПроцедуры

Обработка проведения документа «Поступление товаров» выполнена с помощью конструктора движений и интереса не представляет, так как при поступлении на склад контроль остатков не нужен.

Иногда контроль остатков реализуют и для документа «Поступление товаров» – чтобы при отмене проведения или перепроведении документа не образовался отрицательный остаток.

Например, на склад поступили 10 новых телевизоров LG, 6 из них было продано. Если в документе поступления 10 шт. исправить на 5 шт. – образуется отрицательный остаток «минус 1 шт.».

В типовой УТ 11 подобный контроль включается с помощью функциональной опции «Контролировать товары организаций при отмене приходов».

При проведении документа «Реализация товаров» необходимо организовать контроль остатков. Если товара на остатках недостаточно, документ не проводится и выдается диагностическое сообщение. В этом и состоит решаемая задача.

Мы намеренно работаем над простой задачей, когда себестоимость при списании не рассчитывается. Это позволит нам сосредоточиться именно на нюансах контроля остатков.

Примечание – представленные ниже алгоритмы разработаны для обучения и должны быть максимально понятными.
Их можно оптимизировать, но тогда «коэффициент понимания» будет ниже, поэтому в данной статье мы на этом не останавливаемся.

Естественно, Вы можете оптимизировать их самостоятельно, либо пройти наш курс по Ускорению и Оптимизации 1С :)

Как Вы уже поняли, решение задачи может быть выполнено двумя способами. Начнем с методики, которая применялась ещё со времен «1С:Предприятие 8.0».

Старая методика контроля остатков

Принцип старой методики контроля остатков следующий: проверяем, есть ли остаток товаров в нужном количестве. Если есть – списываем, если нет – сообщаем об ошибке.

Алгоритм в старой методике состоит из нескольких блоков:

  1. Запросом получаются остатки товаров и данные документа
  2. В цикле выполняется контроль достаточности товаров
  3. Если товаров недостаточно, то документ не проводится
  4. Если товаров достаточно – выполняются движения-расход

Вот так выглядит программный код:

Процедура ОбработкаПроведения(Отказ, РежимПроведения)
   
    //  1. Очистка старых движений регистра
    Движения.СвободныеОстатки.Очистить();
    Движения.СвободныеОстатки.Записывать = Истина;
    Движения.Записать();
   
    //  2. Получение запросом данных документа и остатков регистра
    Запрос = Новый Запрос;
    Запрос.Текст =
        "ВЫБРАТЬ
        |   Товары.Номенклатура КАК Номенклатура,
        |   СУММА(Товары.Количество) КАК Количество
        |ПОМЕСТИТЬ Товары
        |ИЗ
        |   Документ.РеализацияТоваровУслуг.Товары КАК Товары
        |ГДЕ
        |   Товары.Ссылка = &Ссылка
        |
        |СГРУППИРОВАТЬ ПО
        |   Товары.Номенклатура
        |
        |ИНДЕКСИРОВАТЬ ПО
        |   Номенклатура
        |;
        |
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        |   Товары.Номенклатура КАК Номенклатура,
        |   ПРЕДСТАВЛЕНИЕССЫЛКИ(Товары.Номенклатура) КАК НоменклатураПредставление,
        |   Товары.Количество КАК Количество,
        |   ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
        |ИЗ
        |   Товары КАК Товары
        |       ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СвободныеОстатки.Остатки(
        |               &МоментВремени,
        |               Номенклатура В
        |                   (ВЫБРАТЬ
        |                       Товары.Номенклатура КАК Номенклатура
        |                   ИЗ
        |                       Товары КАК Товары)) КАК Остатки
        |       ПО Товары.Номенклатура = Остатки.Номенклатура";
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
    РезультатЗапроса = Запрос.Выполнить();
   
    //  3. Обход результатов запроса
    ВыборкаТовары = РезультатЗапроса.Выбрать();
   
    Пока ВыборкаТовары.Следующий() Цикл
       
        //  4. Проверка на достаточность товаров
        Дефицит = ВыборкаТовары.Количество - ВыборкаТовары.Остаток;
        Если Дефицит>0 Тогда
            Отказ = Истина;
            Сообщение = Новый СообщениеПользователю;
            Сообщение.Текст = "Товара "+ВыборкаТовары.НоменклатураПредставление+" недостаточно в количестве "+Дефицит+" шт.";
            Сообщение.Сообщить();
        КонецЕсли;
       
        //  5. Переход в начало цикла, если были ошибки
        Если Отказ Тогда
            Продолжить;
        КонецЕсли;
       
        //  6. Выполнение движений в регистры
        Движение = Движения.СвободныеОстатки.ДобавитьРасход();
        Движение.Период = Дата;
        Движение.Номенклатура = ВыборкаТовары.Номенклатура;
        Движение.Количество = ВыборкаТовары.Количество;
    КонецЦикла;
   
    //  7. Установка флага записи движений в конце транзакции
    Движения.СвободныеОстатки.Записывать = Истина;
   
КонецПроцедуры

Прокомментируем ключевые точки алгоритма.

1. Очистка старых движений регистра

Ниже в алгоритме будет запрос к остаткам регистра.

Если текущий документ был ранее проведен, то существует вероятность получить в запросе старые движения документа – это серьезная проблема.

Когда возможна такая ситуация? Когда дата документа сдвигается вперед.

Покажем на примере, к чему это приведет:

  1. Остаток ламп настольных 10 шт.
  2. Проводится документ от 16.02.17, списываем 6 ламп
  3. В документе меняется дата на 17.02.17 (дату можно сместить хоть на 1 секунду вперед), перепроводим документ.

Если очистку движений не выполнять, то система сообщит о нехватке 2 штук. Почему? Да потому что старые движения документа списали 6 из 10 имеющихся ламп. Далее система пытается списать еще 6 штук, а на остатках есть только 4.

Проблема решается в 3 строки кода:

  • Выполняется очистка набора записей (он мог быть прочитан на форме или в предыдущих обработчиках)
  • У набора записей устанавливается флаг «Записывать»
  • Выполняется запись всех наборов, у которых установлен флаг «Записывать»

Рекомендуется использовать запись через коллекцию «Движения», чтобы избежать возможных взаимоблокировок — когда в разных документах одни и те же регистры записываются в разной последовательности.

Строго говоря, мы можем управлять очисткой движений при проведении документов:

Настройка режима удаления движений в документах

Вариант с удалением движений при отмене проведения является рекомендуемым – мы сами управляем, когда нужно действительно удалять движения.

2. Получение запросом данных документа и остатков регистра

Запрос состоит из двух пакетов:

  • В первом получаются сгруппированные данные табличной части – создается временная таблица
  • Во втором запросе к данным документа присоединяются остатки из регистра.

На что стоит обратить внимание в этом запросе:

  1. При создании временной таблицы индексируется поле, по которому далее будет выполняться соединение – это сделано для оптимальной производительности
  2. Момент получения остатков – соответствуют положению документа на временной оси
  3. Остатков в регистре может не быть – поэтому выполняется левое соединение и для ресурса «Количество» применяется функция «ECТЬNULL» – значение NULL приводится к нулю.

3. Обход результатов запроса

Разработанный запрос содержит сгруппированные данные документа и остатки по номенклатурным позициям.

В цикле обходим результат этого запроса.

4. Проверка на достаточность товаров

Определяем дефицит по товарам.

Если дефицит больше нуля, значит, товара не хватает:

  • Выдаем диагностическое сообщение
  • Выставляем параметр «Отказ» обработки проведения в значение «Истина»

Если «Отказ» будет равен «Истина», то результат транзакции проведения документа не будет зафиксирован. Говоря простым языком – это команда системе не проводить данный документ.

5. Переход в начало цикла, если были ошибки

Если на этом или предыдущих шагах цикла были ошибки (Отказ = Истина), то тогда нет смысла формировать движения. Всё равно в базу данных они не будут записаны.

6. Выполнение движений в регистры

Если проверка остатков прошла успешно, формируем движение-расход.

7. Установка флага записи движений в конце транзакции

Если данный флаг не установить, то движения НЕ будут записаны.

В конце транзакции проведения документа записываются только те наборы записей, у которых установлен флаг «Записывать».

Справедливости ради отметим, что установка свойства “Записывать” набора записей имеет смысл при одном условии – в свойстве документа “Запись движений при проведении” должно быть указано значение “Записывать выбранные”:

Свойство документа Запись движений при проведении - Записывать выбранные и Записывать модифицированные

Однако именно значение “Записывать выбранные” является стандартом де-факто:

  • Оно используется в типовых решениях
  • Устанавливается по-умолчанию при создании новых документов.

Другое значение свойства – “Записывать модифицированные” является устаревшим и в современных конфигурациях практически не встречается.

Новая методика контроля остатков

В новой методике используется принцип: списываем необходимые товары, далее проверяем – образовались ли отрицательные остатки по товарам документа. Если да, то нужно откатить проведение документа.

Как видите, принципиальная разница в моменте контроля остатков:

  • Старая методика – сначала проверяем остаток, потом списываем
  • Новая методика – сначала списываем, потом проверяем остаток.

В результате программный код будет выглядеть следующим образом:

Процедура ОбработкаПроведения(Отказ, РежимПроведения)
   
    //  1. Получение запросом данных документа
    Запрос = Новый Запрос;
    Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
    Запрос.Текст =
        "ВЫБРАТЬ
        |   Товары.Номенклатура КАК Номенклатура,
        |   СУММА(Товары.Количество) КАК Количество
        |ПОМЕСТИТЬ Товары
        |ИЗ
        |   Документ.РеализацияТоваровУслуг.Товары КАК Товары
        |ГДЕ
        |   Товары.Ссылка = &Ссылка
        |
        |СГРУППИРОВАТЬ ПО
        |   Товары.Номенклатура
        |
        |ИНДЕКСИРОВАТЬ ПО
        |   Номенклатура
        |;
        |
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        |   Товары.Номенклатура КАК Номенклатура,
        |   Товары.Количество КАК Количество
        |ИЗ
        |   Товары КАК Товары";
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    РезультатЗапроса = Запрос.Выполнить();
   
    //  2. Формирование движений-расход регистра
    Движения.СвободныеОстатки.Очистить();
    ВыборкаТовары = РезультатЗапроса.Выбрать();
    Пока ВыборкаТовары.Следующий() Цикл
        Движение = Движения.СвободныеОстатки.ДобавитьРасход();
        Движение.Период = Дата;
        Движение.Номенклатура = ВыборкаТовары.Номенклатура;
        Движение.Количество = ВыборкаТовары.Количество;
    КонецЦикла;
   
    //  3. Запись движений в БД
    Движения.СвободныеОстатки.Записывать = Истина;
    Движения.Записать();
   
    //  4. Запрос, получающий отрицательные остатки из регистра
    Запрос.Текст =
        "ВЫБРАТЬ
        |   Остатки.Номенклатура КАК Номенклатура,
        |   ПРЕДСТАВЛЕНИЕССЫЛКИ(Остатки.Номенклатура) КАК НоменклатураПредставление,
        |   -Остатки.КоличествоОстаток КАК Дефицит
        |ИЗ
        |   РегистрНакопления.СвободныеОстатки.Остатки(
        |           &МоментВремени,
        |           Номенклатура В
        |               (ВЫБРАТЬ
        |                   Товары.Номенклатура КАК Номенклатура
        |               ИЗ
        |                   Товары КАК Товары)) КАК Остатки
        |ГДЕ
        |   Остатки.КоличествоОстаток < 0";
   
    ГраницаКонтроля = Новый Граница(МоментВремени(), ВидГраницы.Включая);
    Запрос.УстановитьПараметр("МоментВремени", ГраницаКонтроля);
    РезультатЗапроса = Запрос.Выполнить();
   
    //  5. Вывод сообщений о недостатке товаров
    Если Не РезультатЗапроса.Пустой() Тогда
        Отказ = Истина;
        ВыборкаОшибки = РезультатЗапроса.Выбрать();
        Пока ВыборкаОшибки.Следующий() Цикл
            Сообщение = Новый СообщениеПользователю;
            Сообщение.Текст = "Товара "+ВыборкаОшибки.НоменклатураПредставление+" недостаточно в количестве "+ВыборкаОшибки.Дефицит+" шт.";
            Сообщение.Сообщить();
        КонецЦикла;
    КонецЕсли;
   
КонецПроцедуры

Разберем ключевые точки алгоритма.

1. Получение запросом данных документа

Этот запрос нужен для группировки данных табличной части документа.

Дальше эти данные будут использованы для создания движений.

Обратите внимание, что в первом запросе пакета создается временная таблица – она будет использоваться и в следующем запросе. Это возможно благодаря менеджеру временных таблиц, который создан для этого запроса.

2. Формирование движений-расход регистра

В цикле записываются данные из документа в регистр – то есть выполняется безусловное (без проверки) списание товаров.

3. Запись движений в БД

Чтобы остатки в регистре изменились, движения нужно записать.

4. Запрос, получающий отрицательные остатки из регистра

А теперь простым запросом выбираем отрицательные остатки по товарам документа.

Именно здесь используется созданная на первом шаге временная таблица – накладывается условие на номенклатуру (для этого мы не создаем новый объект типа «Запрос», а используем созданный ранее).

Обратите внимание, как передается момент времени – используется тип данных «Граница». Остатки нужно получить на момент времени сразу ПОСЛЕ текущего документа.

Можно ли было получить остатки без границы, например, прибавив к дате документа 1 секунду?

Нет! Ведь в одной секунде может быть большое число документов. Поэтому единственный правильный вариант – использовать вид границы «Включая».

5. Вывод сообщений о недостатке товаров

Если результат запроса не пустой, значит, есть отрицательные остатки – в этом случае документ не проводится и выдаются сообщения обо всех ошибках.

Преимущества контроля остатков по новой методике

Итак, оба алгоритма решают одну и ту же задачу.

Разница между алгоритмами видна, но преимущества не очевидны.

Поэтому давайте подчеркнем их:

  1. Нет необходимости очищать старые движения документа. По сути это операция записи в БД пустого набора движений и удаление существующих движений – это довольно ресурсоемкие операции
  2. Запрос, получающий данные по отрицательным остаткам, обращается только к одной таблице – нет необходимости делать левое соединение с данными документа и применять функцию «ЕСТЬNULL()»

Кроме этого, при нормальном течении бизнес-процессов пользователь указывает количество, не превышающее остаток на складе.

В этом случае второй запрос не вернет никаких данных и проведение документа будет максимально быстрым.

А так ли важны эти миллисекунды?

На базах с небольшим количеством данных и пользователей разница будет незаметна. Но в нагруженных системах с десятками пользователей цена каждой миллисекунды высока.

Кроме того, на экзамене 1С:Специалист по платформе нужно обязательно использовать новый способ контроля остатков, если это допускает конкретная задача.

Ok, значит, нужно всегда использовать новую методику, верно?

Нет, это не так!

Новая методика может использоваться только в том случае, если для проведения документа есть все необходимые данные в самом документе.

То есть для получения данных не нужно обращаться к регистрам, по которым производится контроль остатков.

Так, например, если в регистре «Свободные остатки» учитывалась бы и сумма, то пришлось бы использовать старую методику контроля.

Почему?
Да просто, чтобы рассчитать сумму списания себестоимости, придется обратиться к регистру. И раз уж мы делаем этот запрос ДО формирования движений, то будет иметь смысл сразу получить доступный остаток.

К слову сказать, в типовой «1С:Управление торговлей 11» реализован контроль остатков по новой методике, а в «1С:Бухгалтерии 8» – по старой методике.

Но это ещё не все!

Представленные выше алгоритмы можно использовать лишь в учебных целях. Дело в том, что в них не учитываются управляемые блокировки, которые необходимо применять, если в системе работает более одного пользователя.

Блокировкам для обоих методик контроля остатков посвящена отдельная статья. Также в данной статье мы решаем более сложную задачу – кроме контроля остатков выполняем расчет себестоимости списываемой номенклатуры. Рекомендуем её вдумчиво изучить.

А для «затравки» лишь скажем, что установка блокировки в новой методике делается очень просто – и это еще одно преимущество нового способа контроля остатков.

Итоги

Подведем краткие итоги.

Мы рассмотрели две методики контроля остатков, каждая из которых применяется в современных типовых конфигурациях.

Ключевое различие между методиками в моменте контроля остатков:

  • Старая методика – контроль до записи движений в регистры
  • Новая методика – контроль после записи движений в регистры

В общем случае новая методика является более эффективной, но применима она не всегда.

Критерий применимости – если для формирования движений нет необходимости обращаться к данным контролируемого регистра, можно использовать новую методику.

Если говорить о контроле остатков по номенклатуре, то применение новой методики возможно, когда данные о себестоимости и складских остатках хранятся в разных регистрах.

И в завершение примеры из типовых конфигураций:

  • В УТ 11 есть 2 основных регистра для учета номенклатуры: Свободные остатки (количество) и Себестоимость товаров (данные о себестоимости) – используется новая методика
  • В БП 3.0 данные о себестоимости и остатках хранятся в одном регистре бухгалтерии – используется старая методика контроля остатков.

Выгрузки ИБ и PDF-версия статьи для участников группы ВКонтакте

Мы ведем группу ВКонтакте – http://vk.com/kursypo1c.

Если Вы еще не вступили в нее – сделайте это сейчас, и в блоке ниже (на этой странице) появятся ссылки на скачивание материалов.


Статья в PDF-форматеСтатья в PDF-формате
Вы можете скачать эту статью в формате PDF по следующей ссылке: Ссылка доступна для зарегистрированных пользователей)

ИБ с новой методикой контроля остатков:
Ссылка доступна для зарегистрированных пользователей)

ИБ со старой методикой контроля остатков:
Ссылка доступна для зарегистрированных пользователей)

ИБ разрабатывались на платформе 1С:Предприятие 8.3.9.1850.

Комментарии / обсуждение (133):

  1. godwar

    Добрый день, видел такую фразу в критериях выставления оценки по экзамену(ATT)

    “Не реализована возможность корректного перепроведения документов задним числом”
    Что это означает?

    • Василий Ханевич

      Добрый день!
      Это значит, что если существующий проведенный документ перепроводится задним числом (и при этом данные самого документа не изменяются), то новые движения документа должны быть такими же, как и до перепроведения.

      Пример. В условии задачи указано, что учетная политика может изменяться со временем. Значит, нужно сохранять историю изменений учетной политики. При проведении документа задним числом нужно получать именно те настройки учетной политики, которые действовали на момент времени проводимого документа, а не те, которые действуют сейчас. Поэтому для хранения настроек учетной политики логично использовать периодический регистр сведений, тогда в коде достаточно будет получать данные из виртуальной таблицы СрезПоследних.

      Если же реализовать хранение значения учетной политики, например, в справочнике, то, с одной стороны, если не учесть возможность её изменения и не реализовать способа получения её значения на определенный момент времени, это может привести к снижению оценки. С другой стороны, если даже добавить в справочник реквизиты для хранения периода действия учетной политике, то такой вариант решения будет нерациональным – его реализация (заполнение и получение нужных значений) будет более громоздкой и трудоемкой, чем при использовании регистра сведений. Да и у экзаменатора могут возникнуть вполне закономерные сомнения, что сдающий экзамен знаком с этим механизмом и умеет им пользоваться.

  2. gusenica1337

    День добрый. Такой вопрос. Я правильно понимаю, что при списании по партиям ВСЕГДА будет использоваться старая методика проведения? Потому что нам надо знать, сколько товара находится в каждой партии, чтобы списывать нужное число товара

    • Василий Ханевич

      Добрый день!
      Новая методика может использоваться только в том случае, если для проведения документа есть все необходимые данные в самом документе.
      Например, учет себестоимости ведется с точностью до партии, в документе реализации пользователь вручную указывает партии, из которых нужно произвести списание. В таком случае можно использовать новую методику.
      А так Вы правильно подметили, что при списании по ФИФО чаще будет использоваться старая методика, т.к. сведения о списываемых партиях отсутствуют в самом документе.

  3. Aleksandrs

    Вообще не понятно как по “новой” методике спишутся нужные партии… Чтобы списать партии по любому же надо прочитать остаток партий и списать по ФИФО….

    • Василий Ханевич

      Добрый день!
      В статье указано, что новая методика может использоваться только в том случае, если для проведения документа есть все необходимые данные в самом документе.
      В Вашем примере сведения о списываемых партиях отсутствуют в самом документе, поэтому нужно воспользоваться старой методикой.

  4. Роман

    “Запрос, получающий данные по отрицательным остаткам, обращается только к одной таблице – нет необходимости делать левое соединение с данными документа и применять функцию «ЕСТЬNULL()»”

    Здравствуйте. А если все-таки сделать левое соединение с табличной частью в этой методике это будет считаться ошибкой?

    • Павел Сериков

      Здравствуйте.

      Если можно решить более простым способом (в данном случае как раз-таки можно обойтись без соединения), то искусственное усложнение, сверх необходимого, будет считаться ошибкой (тип ошибки: “Неоптимальное, неэффективное решение”).

  5. Тимур

    А если я захочу из документа РеализацияТоваровУслуг сделать возврат некоторого количества, как это делать

    • Павел Сериков

      Здравствуйте.

      В этом случае создается другой документ, обычно называется “Возврат от покупателя”. Суть его движений – отмена исходной реализации, т.е. выполняется расход с минусом – по той номенклатуре, которая была в исходном документе реализации и с количеством, не превышающим количество реализации.

      Только какое отношение данный документ имеет к теме настоящей статьи? По форме это приходный документ, по сути – сторнирующий, никакого контроля остатков здесь не будет, т.к. остатков проданных товаров просто нет (остатки были списаны при продаже).

  6. Новиков Эдуард

    [Движения.СвободныеОстатки.Очистить();] – Не нужен этот операнд (в новой методике). Коллекция движений ещё пустая.
    [Движения.СвободныеОстатки.Очистить()] – операнд в обработке проведения, относящийся к новой методике, на мой взгляд – лишний.

    • Павел Сериков

      Здравствуйте.

      Свойство документа Движения содержит список наборов записей регистров, по которым документ может выполнять движения (является регистратором).
      Движения – это объект в памяти. При открытии документа на редактирование объект Движения может заполняться: из базы данных в него могут быть считаны все имеющиеся движения данного документа (иначе говоря, все записи регистров, для которых данный документ является регистратором).

      При работе с обычными формами заполнение объекта Движения производится каждый раз при открытии формы документа.

      При работе с управляемыми формами заполнение объекта Движения системой производится не всегда, а только если выполнены некоторые специфичные настройки на форме (например, если для свойства Движения в форме установлен признак “Использовать всегда“ или же если движения документа помещены на форму). По умолчанию (если на созданной форме специально не изменить настройки) заполнение объекта Движения не производится, поэтому при начале проведения документа объекта Движения будет пуст, и необходимость его явной очистки отсутствует.

      Таким образом, если используются управляемые формы и специально не выполнены настройки на форме, принуждающие систему считывать движения документа, то объект Движения при начале обработки проведения будет пуст, и очищать его не требуется. В противном случае, а также для обычных форм, объект Движения при начале обработки проведения будет заполнен существующими движениями документа, и их нужно будет предварительно удалить.

      Поэтому по соображениям универсальности метод Движения.СвободныеОстатки.Очистить() здесь не является лишним.

      • Новиков Эдуард

        Спасибо. Уже давно под руками только УФ. Универсальность – это правильно.

      • gesperid

        Что-то не удалось воспроизвести в обычных формах – авто считывание после открытия формы.

        • Василий Ханевич

          Добрый день!
          Прикрепил пример на обычных формах – ДвиженияОбычныеФормы.zip.
          Открываем в пользовательском режиме форму уже проведенного документа, проводим его. В отладчике видно, что движения уже заполнены в самом начале обработки проведения:
          Отладка

              • gesperid

                Спасибо. Посмотрел базу.
                Открываю форму и провожу – в обработке проведения движения не прочитаны.
                [url=https://imageup.ru/img72/4401700/bezymiannyi-risunok.png.html][img]https://imageup.ru/img72/thumb/bezymiannyi-risunok4401700.jpg[/img][/url]
                При повторном проведении, если не закрывать форму – движения прочитаны (как на вашем скриншоте).
                Оно и понятно, мы формировали движения для проведения – они остались в объекте.
                Пробовал также создавать кастомную основную форму: без проведения ПриОткрытии не удалось получить “автопрочитанные” движения в форме как в ответе Павла.
                Или я что-то упускаю?

                • Василий Ханевич

                  Давайте разбираться подробно.

                  Изначальный вопрос был в том, нужно ли использовать очистку движений в обработке проведения.
                  Это нужно делать, если используется обычное приложение.
                  Поэтому для универсальности такие конструкции оставлялись в коде.

                  >>При повторном проведении, если не закрывать форму – движения прочитаны (как на вашем скриншоте).
                  Оно и понятно, мы формировали движения для проведения – они остались в объекте.

                  Да, правильно, именно так в обычном приложении и работает.
                  Поменяйте для конфигурации основной режим запуска на Управляемое приложение. И такое поведение воспроизводиться не будет.

                  Также можно обратить внимание, что конструктор движений будет формировать разный программный код в зависимости от основного режима запуска. И при использовании обычного приложения будет добавлять строку кода с очисткой движений по регистру.
                  Это появилось очень давно. В файле с описанием изменений в платформе V8Update.htm можно найти вот такую цитату:
                  Версия 8.2.11
                  Изменения, требующие изменений в конфигурациях:
                  В конструкторе движений документов реализовано включение вызова удаления существующих движений в наборах записей, по которым формируются движения, если основной режим конфигурации «Обычное приложение» и у документа установлен режим «Удалять автоматически при отмене проведения» или «Не удалять автоматически». Рекомендуется выполнить соответствующие изменения в конфигурациях.

                  Потенциальная проблема может возникнуть при повторном проведении из обычной формы. При проведении из списка или из управляемой формы такой ситуации не возникает. Отличия в поведении объясняются следующим:
                  – Проведение из списка каждый раз создает новый объект.
                  – Проведение из обычной формы использует один и тот же объект.
                  – Проведение из управляемой формы каждый раз создает новый объект.
                  Поэтому очистка движений в модуле необходима для того, чтобы очистить движения в памяти, когда один и тот же экземпляр объекта в памяти проводится несколько раз.

                  Вот так этот механизм работает.

  7. Евгений

    Добрый день!
    Вопрос по новой методике.
    2. Формирование движений-расход регистра
    В цикле записываются данные из документа в регистр – то есть выполняется безусловное (без проверки) списание товаров.

    3. Запись движений в БД
    Чтобы остатки в регистре изменились, движения нужно записать.

    Поясните, пожалуйста, механизм отмены записи движений в регистр при Отказ=Истина…

    • Павел Сериков

      Здравствуйте.

      Проведение документа (точнее – запись документа в режиме проведения) производится в транзакции. Для того чтобы произведенные изменения перенеслись а базу, транзакция должна быть зафиксирована.
      Если при окончании обработки проведения переменная Отказ имеет значение Ложь, то транзакция будет зафиксирована, и сформированные движения регистра попадут в базу.
      Если же переменная Отказ имеет значение Истина, то транзакция будет отменена, и сформированные движения регистра будут потеряны.

  8. Евгений

    Добрый день! А почему в старой методике проведения нет “установки” блокировок перед чтением остатков?

    • Павел Сериков

      Здравствуйте.

      В данной статье старая и новая методики проведения рассмотрены несколько упрощенно, чтобы нагляднее продемонстрировать разницу между ними. В частности, для упрощения здесь не затронут вопрос установки блокировок. Об этом упомянуто в данной статье в пункте “Но это ещё не все!”.
      В реальных модулях установка блокировок, конечно же, потребуется.

      Для старой методики код установки помещается до выполнения запроса на чтение остатков регистра и выглядит примерно так:

      // 7. Управляемая блокировка данных регистра
      Блокировка = Новый БлокировкаДанных;
      ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.СебестоимостьТоваров");
      ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
      ЭлементБлокировки.ИсточникДанных = РезультатНоменклатура;
      ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
      Блокировка.Заблокировать();

      Рекомендую ознакомиться с другой, более полной статьей по данной тематике: “Методика оперативного проведения и управляемые блокировки в 1С:Предприятие 8.3 (обновление 2017 года)”

      Кроме того, ниже приведены ещё несколько ссылок на статьи по данной тематике:
      “[ Вопрос дня ] Какие блокировки используются в «старой» и «новой» методиках проведения документов?” – Здесь приведено сравнение подходов к блокировке данных для старой и новой методик.
      “[ Нюансы платформы 1С:Предприятие 8 ] – Как работает свойство БлокироватьДляИзменения” – Здесь уже копнули глубже и рассмотрели технические нюансы работы свойства “БлокироватьДляИзменения”.

  9. Илья Пак

    Здравствуйте.
    В преимуществах новой методики указано преимущество “Нет необходимости очищать старые движения документа”. Но данная операция выполняется как в старой методике, так и в новой.
    Или я что-то не так понял?

    • Ольга Шапкина

      Добрый день!
      В новой методике предварительная очистка старых движений регистра и запись пустого набора движений не происходит.
      Для старой методики в данном примере это вот этот кусок кода:

       //  1. Очистка старых движений регистра
          Движения.СвободныеОстатки.Очистить();
          Движения.СвободныеОстатки.Записывать = Истина;
          Движения.Записать();
      • Spakus

        В тексте новой методики у вас почему-то применяется очищение записей:
        //  2. Формирование движений-расход регистра
            Движения.СвободныеОстатки.Очистить();
            ВыборкаТовары = РезультатЗапроса.Выбрать();
            Пока ВыборкаТовары.Следующий() Цикл
                Движение = Движения.СвободныеОстатки.ДобавитьРасход();
                Движение.Период = Дата;
                Движение.Номенклатура = ВыборкаТовары.Номенклатура;
                Движение.Количество = ВыборкаТовары.Количество;
            КонецЦикла;
           
            //  3. Запись движений в БД
            Движения.СвободныеОстатки.Записывать = Истина;
            Движения.Записать();

        Я так понимаю это опечатка?

        • magic1s

          Очистка перед добавлением новых движений, запись “очистки” и добавленных движений происходит один раз.
          В “старой” происходит очистка с записью, перед запросом остатков. И плюс запись сформированных движений в конце обработки проведения.

  10. Анвар

    Добрый день. Зачем в первом запросе вначале происходит очищение движений? Как понимаю чтобы движения не мешались в запросе, но ведь в запросе можно указать Граница.Исключая.

  11. RickJames

    Добрый день!
    Подскажите в чем дело, столкнулся с такой ситуацией, я не добавляю условие на Остаток < 0, при запросе по новой методике и все прекрасно работает(т.е. в РезультатЗапроса попадают только отрицательные остатки по ТЧ Документа), в чем может быть дело?
    Не включаю следующее условие:
    |ГДЕ
    | Остатки.КоличествоОстаток < 0
    Платформа 8.3.15.1565

    • Вячеслав Вязигин

      День добрый!

      Ответ тут может быть только один – у Вас в регистре, в момент выполнения запроса, только отрицательные остатки, положительных нет.

  12. Олег

    Добрый день
    Подскажите, пожалуйста, касательно момента, что новая методика используется только, если все данные можно получить сразу из документа.
    Если например, идет также расчет себестоимости по средней из регистра ОстаткиТоваров

    Да, я обращаюсь к этому регистру за СуммаОстаток. И вы предлагаете использовать старую методику – идти по результату запроса и смотреть, где КоличествоРасход будет больше КоличествоОстаток, и, если все ОК, то записывать движения (себестоимость рассчитывается в запросе, допустим)

    Но я могу же в этом случае не использовать цикл, а записать данные из запроса ( с рассчитанной в нем себестоимостью) в регистр, а потом сделать запрос на отрицательные остатки

    Получается вместо цикла по запросу (по старой методике) я сделаю второй раз запрос к регистру остатков, чтобы найти отрицательные. Разве это ошибка? Цикл по старой методике будет быстрее чем второй запрос?

    • Ольга Шапкина

      Добрый день!
      Тут ключевым моментом является то, что, следуя новой методики, вам придется дважды обратиться к одному регистру. Для высоко нагруженных информационных баз это может быть критично, да и на экзамене это будет считаться ошибкой. На базе с небольшим количеством данных разницу в производительности между циклом по старой методике и вторым запросом по новой вы скорее всего не заметите.

  13. Алексей

    Спасибо за статью. Хочу обратить внимание на разъяснение преподавателя УЦ-1 и экзаменатора (и составителя задач для экзамена) Павла Белоусова о том, когда применять две обсуждаемые методики: на ютубе ролик “Методика проведения документов в задачах оперативного и бухгалтерского учета – онлайн от УЦ 1”
    youtu.be/1SIQBNrSIOY

    • Kikoong

      По ссылке ни слова о том когда применять две обсуждаемые методики. Сказано лишь, что об этом идет речь в их онлайн курсе.

  14. Alex2016

    Добрый день!
    Зачем в старом методе контроля остатков (п.3 алгоритма) в обходе выборки делаются и движения. Ведь может получиться так, что у 100 первых товаров в выборке дефицита нет, а у 101-го товара дефицит есть. Тогда мы выполняем лишние строки кода.
    Не лучше ли вынести движения из этого цикла в отдельный цикл, который будет выполняться, если дефицита нет, и Отказ остался = Ложь?

    • Вячеслав Вязигин

      День добрый!

      Движения в данном пункте только формируются, но не записываются в базу данных. Вынос формирования движений в отдельный цикл принципиально ничего не поменяет.

  15. Alex2016

    Добрый день!
    Зачем в запросе в старом методе в п.2. в тексте запроса выбирается 2 поля Товары.Номенклатура и ПредставлениеСсылки(Товары.Номенклатура).
    Разве недостаточно ПредставленияСсылки?

    • Вячеслав Вязигин

      День добрый!

      Представление используется для формирования текстового сообщения в случае недостатка товара в количестве, а сама ссылка используется в формировании движений на шестом шаге. Одного представления недостаточно.

  16. Яковенко Илья

    Насколько правильно делать в старой методике проведения вот так:

    //Снимаем галку разделение итогов, чтобы заблокировать записи по “Удаляемым” данным. Чтобы при отказе транзакции другой пользователь между контролем остатков и отказом транзакции не списал освободившуюся номенклатуру
    Движения.ОстаткиНоменклатуры.БлокироватьДляИзменения = Истина;
    //Если работаем с обычными формами
    Движения.ОстаткиНоменклатуры.Очистить();
    //Если режим записи не оперативный, то мы будем использовать в дальнейшем выбора остатки с МоментВремени() который не включает движения документа
    //Если режим записи оперативный, то мы очищаем движения, так как при чтении остатков использование МоментВремени() все равно будет брать остатки влючая движения данного документа.
    Если Режим = РежимПроведенияДокумента.Оперативный Тогда
    //Пишем пустой набор записей, флаг ОстаткиНоменклатуры.Записывать = Истина не снимается
    Движения.ОстаткиНоменклатуры.Записать();
    КонецЕсли;

    Интересует нужно ли снимать разделение итогов. И реально ли при оперативном проведении перепроведение приведет к тому что будут взяты остатки которые включают движения данного документа?

    • Яковенко Илья

      Обсуждение данного вопроса на форуме Чистова
      http://forum.chistov.pro/index.php?topic=1999.30

      пост 1

      Допустим: в уже имеющемся проведённом документе “Реализация” продан товар “стул” в количестве одна штука, при этом на складе их ноль штук.
      Затем пользователь заходит в документ и меняет, “стул” на “кресло”. Далее нажимает кнопку провести, и запускается обработка проведения.
      В момент выполнения строки: Записать() движение в регистре с позицией “стул” очищается и запишется в базу данных, в результате на остатке на складе появится одна позиция “стул”.
      Далее внутри тойже обработки проведения наложится блокировка на “кресло” и начнётся транзакция.
      При этом, по скольку на складе появился один незаблокированный “стул” на остатке, другой пользователь в это время возьмёт и побыстрому проведёт, этот “стул” в другом документе “реализация” и на складе станет ноль позицый “стул”.
      Затем уже в нашем документе, при попытке списать заменённый стул на кресло, произошла какая-то ошибка, и мы решили откатить транзакцию. т.е. “стул” возвращается на место.
      И в результате таких действий, стул будет в количестве “минус один” на складе.
      Вот для того, чтобы такого не произошло, нужно заблокировать, не только новые позиции, но и старые которые были в документе, до момента окончания текущей транзакции записи, до тех пор, пока мы не будем точно уверены, что не планируется её откат.

      пост 2

      Первый случай когда надо использовать Движения.ОстаткиТоваров.БлокироватьДляИзменения=Истина;

      Старая методика проведения:
      Движения.ОстаткиТоваров.БлокироватьДляИзменения=Истина;
      Движения.ОстаткиТоваров.Записать();

      Блокировка=Новый БлокировкаДанных;
      Блок=Блокировка.Добавить(“РегистрНакопления.ОстаткиТоваров”);
      Блок.Режим=РежимБлокировкиДанных.Исключительный;
      Блок.ИсточникДанных=СписокНоменклатуры;
      Блок.ИспользоватьИзИсточникаДанных(“Номенклатура”,”Номенклатура”);
      Блокировка.Заблокировать();

      Перепроводим существующий документ.
      Такс устанавливаем блокировку… Блокируем Что? Регистр. По какому набору записей??? ФИГ знает толи по пустому толи по старому, а истина где то там—————>…… НО в народе говорят что лучше написать, баллы на экзамене не лишние)). Например: регистр остатки товаров пустой и есть расходная (номенклатура:стол, количество: 1). Заходит пользователь и меняет стол на стул жмет Окей и ждет пока закончится транзакция , в этот момент второй юзер тем же документом расходная видит ага появился стол, щас спишу и списывает. Обидно но транзакция не увенчалась успехом и мы ее отменили. В итоге столы полетели в минуса , вместе с баллами на экзамене. Чтоб такого не случилось пишем Движения.ОстаткиТоваров.БлокироватьДляИзменения=Истина;, тем самым блокируем регистр по старому набору записей.(<————-здесь я вообще не уверен блин!!! ХЭЛП!). В итоге второй юзер вместе со своей расходной попадает в очередь, а потом получает отказ. Счастлив экзаменатор, сдающий, целы баллы).

      Второй случай когда надо использовать Движения.ОстаткиТоваров.БлокироватьДляИзменения=Истина;

      Новая методика проведения , у регистра накопления стоит свойство (в значение истина), разделять итоги. В таблицу итогов попадает разделитель который позволяет писать данные нескольким документам у которых одинаковый набор записей (например приходная накладная не должна стоять в очереди), НО гадкий разделитель попадает в блокировку при внесении записей списания. Например проводим одновременно: расходная 1 (блокируем Номенклатура: стол, склад:основной, разделитель1), расходная 2(блокируем Номенклатура: стол, склад:основной, разделитель2). Потом начинаем читать и тут :o. Расходная 1 заблокировала данные позиции и расходная 2 тоже, только по разным разделителям, а читаем остатки мы по всем позициям в целом, в итоге ловим deallock.
      Чтоб такого не получилось пишем злополучное Движения.ОстаткиТоваров.БлокироватьДляИзменения=Истина; отключаем разделитель и вторая расходная попадает в очередь, таким образом первая спокойно все читает и мы радуемся.

      Статья от самого Чистова

      http://1c.chistov.pro/2013/07/blog-post_25.html

      Грязное чтение.
      Что это такое?
      Я не буду вдаваться в теорию (в отличии от вас, вам я советую в теорию копнуть, лишним не будет), поясню на примере:
      Проводим две расходных. И в одной и в другой продаем 5 ложек. А в остатках всего 6. Так получилось, что продавать ложки мы умудрились в один и тот-же момент времени. Что произойдет?
      Первая накладная сформирует движения и начнет читать запрос по остаткам через кэш собственной транзакции, что, собственно, будет делать и вторая накладная. Но ложек-то всего 6, а в сумме две накладные продадут 10… Потому-что не знают о том, что данные в таблицах уже не актуальны…
      Что делать?
      Надо заблокировать данные от параллельного чтения.
      В нашем примере это сделать очень просто. У набора записей есть свойство "БлокироватьДляИзменения". Это, как и свойство "Записывать", лишь маркер указывающий, что необходимо установить блокировку на те записи, которые были сформированы в наборе записей.
      Когда устанавливать свойство "БлокироватьДляИзменения"? Не важно, главное до самой записи данных.
      Когда произойдет блокировка записей? В момент записи данных.
      Что означает эта блокировка?
      Никто параллельно с нами читать данные из регистра по тем товарам, движения по которым были сформированы, не сможет.
      Когда блокировка будет снята?
      При окончании транзакции в которой она началась, в нашем примере, при завершении проведения документа.

    • Евгений Гилев (Мастер-тренер)

      В этом нет никакой необходимости, БлокироватьДляИзменения роли не сыграет (то есть абсолютно ничего не изменит).

      • Илья

        Т.е. Вы хотите сказать что данная ситуация не может возникнуть?

        “Например: регистр остатки товаров пустой и есть расходная (номенклатура:стол, количество: 1). Заходит пользователь и меняет стол на стул жмет Окей и ждет пока закончится транзакция , в этот момент второй юзер тем же документом расходная видит ага появился стол, щас спишу и списывает. Обидно но транзакция не увенчалась успехом и мы ее отменили. В итоге столы полетели в минуса”

          • NewYork00

            Добрый день.
            В статье вы описали как накладываются блокировки и тд, но ответьте, пожалуйста, что произойдет исходя из примера, написанного выше.
            В конечном итоге, если у первого документа прервется транзакция, то остатки будут отрицательные и БлокироватьДляИзменения роли никакой не сыграет?
            Если так, то что нужно сделать, чтобы такого не произошло?
            Спасибо.

            • Евгений Гилев (Мастер-тренер)

              Добрый день!

              Здесь нужно прояснить несколько моментов.
              1. При проведении или перепроведении документа платформа автоматически открывает транзакцию, и она эта транзакция одна на все время проведения. Никаких других вложенных транзакций при проведении (да и вообще в 1С) не бывает.
              2. При выполнении метода Записать() движения с товаром Стул будут удалены и остаток обновится, при этом будет наложена X блокировка. X Блокировка будет держатся с момента наложения и до конца транзакции т.е. до окончания проведения документа. Вот тут и кроется ответ. Читаем внимательно, X блокировка держится до окончания проведения, а следовательно никакой другой документ не сможет списать товар Стул, пока первый документ не будет окончательно проведен.
              3. Крайне рекомендую провести опыты и убедится самостоятельно, для этого нужно запустить 2 сеанс, один из которых под отладкой с точкой останова.

              Блокировка в транзакции

  17. Дионис

    Добрый день!
    Подскажите как сделать, чтобы проверка происходила еще и по складам?
    Допустим есть скдлад1 и склад2, в документах приходов и расходов эти позиции указываются.

    Заранее спасибо!

    • Вячеслав Вязигин

      День добрый!

      Для обоих методик проведения необходимо выполнить общие действия:

      1. В регистр накопления «Свободные остатки» добавляется измерение «Склад».
      2. При проведении документа «Поступление товаров» выполняются движения-приход с учетом склада.

      Движение.Склад = Склад;

      Старая методика контроля остатков

      1. При получении запросом данных документа и остатков регистра в виртуальную таблицу остатков добавляется условие по складу и устанавливается значение параметра.

      Склад = &Склад

      Запрос.УстановитьПараметр("Склад", Склад);

      2. Выполнение движений в регистры также выполняется с учетом склада.

      Движение.Склад = Склад;

      Новая методика контроля остатков

      При формировании движений-расход регистра учитываем склад.

      Движение.Склад = Склад;

      Запрос, получающий отрицательные остатки из регистра ограничиваем складом.

      Склад = &Склад

      Запрос.УстановитьПараметр("Склад", Склад);
  18. Федя

    А подскажите по новой методике ,я правильно понимаю, что если Отрицательные остатки по какой то номенклатуре были до момента проведения нашего документа , то Мы получим ошибку отрицательных остатков и по нашему документу?

    • Вячеслав Вязигин

      День добрый!

      Совершенно верно, неважно, что было до проведения документа. Суть новой методики именно в контроле отрицательных остатков после формирования движений документа.

      При правильной архитектуре системы и корректном учете наличие отрицательных остатков маловероятно)

  19. I-am-a-programmer.ru

    Евгений, возник ещё один вопрос, требующий экспертной рецензии:
    а нельзя ли реализовать новую методику на более легком регистре накопления оборотов?
    Сейчас реализую схему: Заказано покупателем -> Закуплено под заказ -> Отгружено. Как мне видится, идеально было бы сделать оборотный регистр Заказы (Изм: Номенклатура, Заказ; Ресурсы: Заказано, Закуплено, Отгружено) и по нему вести учет, сравнивая обороты при проведении (что бы контролировать: Отгружено <= Закуплено <= Заказано).
    Свойство БлокироватьПриИзменении при проведении блокирует в регистре необходимые сочетания Заказ – Номенклатура из табличной части документов закупки и отгрузки (как я понимаю это свойство), что так же способствует реализации этого механизма.

    Прокомментируйте, пожалуйста, такой подход.

    • Евгений Гилев (Мастер-тренер)

      В общем случае такой подход не является правильным – когда вместо регистра остатков мы используем регистр оборотов с двумя ресурсами, в которых хранится приход и расход.

      Теперь по Вашей ситуации.
      Скорее всего Вам будет требоваться не только обороты, но и остатки – в отчетах по заказам, поставке под заказ и т.д.
      Получается, что остаток у вас будет вычисляться.

      Далее, чтобы получить данные по остатку (в общем случае) Вам нужно будет рассчитывать обороты за большой период, что может быть не оптимальным.

  20. SegaZX

    Здравствуйте. Спасибо за полезную статью. Я вот только один момент не понял:
    1. Если у нас есть 2 регистра накопления:
    -ОстаткиНоменклатуры (Измерение:Номенклатура и ресурс “Количество”) Тут мы храним остатки.
    -СтоимостьНоменклатуры (Измерения: Номенклатура и ресурс “Количество” и “Сумма”). а тут мы храним стоимость.
    то все понятно, мы используем новую методику, остатки проверяем из регистра “ОстаткиНоменклатуры”, Записываем в него движения документа, затем проверяем не ушли ли мы в минус.
    2. А вот если у нас для хранения остатков используется регистр “ОстаткиНоменклатуры”, где Измерения “Номенклатура”, “Партия” и ресурс “Количество”?? или где два ресурса “Количество” и “Сумма”?
    в этом случае мы ведь не можем записать движения в регистр, т.к. мы еще не знаем значение “Партия”. или для того, чтобы в общем проверить ИТОГО (по всем партиям) хватит количества или нет, можно записать движения с пустой партией? и если хватает количество, то уже формировать алгоритм по списанию стоимости по партиям?
    спасибо. Или же нет?

    • Евгений Гилев (Мастер-тренер)

      Добрый день!

      Для использования новой методики нужно использовать 2 регистра.

      Вообще, нужно понимать, что в общем случае 2 регистра (остатки + себестоимость) оптимальнее одного.

      Дело в том, что на практике себестоимость нужно хранить в разрезе организации, поставщиков, подразделений, направлений деятельности и т.д. (посмотрите типовую УТ 11).

      Поэтому оптимально данные по остаткам на складе хранить в отдельном регистре с небольшим количеством измерений.

      • SegaZX

        Спасибо за ответ. Правильно ли я понял, что если мы используем 2 регистра накопления (в частности один из них служит ИМЕННО для котроля остатков), только тогда мы можем использовать новую методику? Я пока что решаю задачи 1С Специалист, поэтому и уточнил.

        • Евгений Гилев (Мастер-тренер)

          Да, новую методику имеет смысл применять, если остатки и себестоимость хранятся в отдельных регистрах.

          Это, например, слабо применимо для регистра бухгалтерии, где обычно и остатки и себестоимость хранятся на одном счете БУ.
          Поэтому для бух. задач зачастую нужно использовать старую методику (если контроль остатков там вообще требуется).

  21. Николай

    Полезная статья, спасибо!
    Единственный вопрос остался: можно ли (нужно ли для экзамена?) сообщение о нехватке номенклатуры выводить с привязкой к ТЧ как в старой методике?

    • Евгений Гилев (Мастер-тренер)

      Точных сведений о том, что за это снижают оценку у нас нет.
      Но имеет смысл реализовать такой функционал. Много времени это не займет :)

  22. Варвар2

    Есть новое предложение: В контроль остатков документе не писать, а написать его в самом регистре. Используя модуль набора записей и процедуры ПередЗаписью(Отказ, Замещение) и
    ПриЗаписи(Отказ, Замещение)

    Для одного регистра я уже написал, вроде работает
    Для второго пишу сейчас, вроде получается.

    Пытался выслать код, но не получилось.

    Выгода этого метода очевидно, ибо документов желающих записать что то, в регистр много, и написаны они разными людьми. И не во всех документах правильно написана защита.

    А если защита написана в самом регистре, то не важно что там написано в самом документе!

    • Евгений Гилев (Мастер-тренер)

      Добрый день!

      Ваш код прошел, он в комментарии ниже.

      Описанный Ваши подход имеет право на существование. Более того, в ряде случае в типовых решениях применяется подобный подход.

      Но всё-таки в подавляющем большинстве документов контроль выполняется в модуле объекта (а точнее в методах общих модулей, которые вызываются из модуля объекта.
      Это связано с тем, что обычно проверка при проведении документа выполняется не по одному регистру, а по нескольким. При использовании Вашего подхода, проверки бы выполнялись в модулях наборов записей этих регистров.

      А это значит, что посылалось бы несколько запросов в БД. Что приведет к снижению производительности системы на больших объемах данных.

      Что касается аргумента “записать что то, в регистр много, и написаны они разными людьми”, то его актуальность уменьшается.
      На текущий момент сложность типовых решений такова, что пускать в конфигуратор (а тем более добавлять документы) малограмотным специалистам не лучшая идея.
      Тем более сам функционал прикладных решений растет, многие задачи решаются простой настройкой конфигурации :)

  23. Варвар2

    А если контроль остатков повесить на сам регистр?
    Примерно так:
    Есть регистр накопления СБК_СодержаниеДрагметалловВНоменкре
    В модуле набора записей регистра написать следующее:

    Процедура ПередЗаписью(Отказ, Замещение)

    Документ=ЭтотОбъект.Отбор.регистратор.Значение; //Выясним какой документ вносит изменения?

    Если ЭтотОбъект.Количество()=0 Тогда
    ПриОтменеПроведения=Новый Запрос;
    ПриОтменеПроведения.Текст=”ВЫБРАТЬ
    |СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Организация,
    |СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Подразделение,
    |СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Номенклатура,
    |СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Драгметалл,
    |СБК_СодержаниеДрагметалловВНоменклатуреОбороты.ПартияДМ,
    |СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Склад,
    |СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Сотрудник,
    |ЕСТЬNULL(ОстаткиАктуальные.КоличествоОстаток, 0) – СБК_СодержаниеДрагметалловВНоменклатуреОбороты.КоличествоПриход + СБК_СодержаниеДрагметалловВНоменклатуреОбороты.КоличествоРасход КАК Остаток
    |ИЗ
    |РегистрНакопления.СБК_СодержаниеДрагметалловВНоменклатуре.Обороты(&Dat0, &Dat0, Регистратор, ) КАК СБК_СодержаниеДрагметалловВНоменклатуреОбороты
    |ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СБК_СодержаниеДрагметалловВНоменклатуре.Остатки КАК ОстаткиАктуальные
    |ПО СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Организация = ОстаткиАктуальные.Организация
    |И СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Подразделение = ОстаткиАктуальные.Подразделение
    |И СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Номенклатура = ОстаткиАктуальные.Номенклатура
    |И СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Драгметалл = ОстаткиАктуальные.Драгметалл
    |И СБК_СодержаниеДрагметалловВНоменклатуреОбороты.ПартияДМ = ОстаткиАктуальные.ПартияДМ
    |И СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Склад = ОстаткиАктуальные.Склад
    |И СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Сотрудник = ОстаткиАктуальные.Сотрудник
    |ГДЕ
    |СБК_СодержаниеДрагметалловВНоменклатуреОбороты.Регистратор = &Регистратор
    |
    |УПОРЯДОЧИТЬ ПО
    | Остаток”;
    ПриОтменеПроведения.УстановитьПараметр(“Dat0”,Документ.Дата);
    ПриОтменеПроведения.УстановитьПараметр(“Регистратор”,Документ);
    ТЗ=ПриОтменеПроведения.Выполнить().Выгрузить();
    Для Каждого ё Из ТЗ Цикл //Проверяем актуальные остатки
    Если ё.Остаток<0 Тогда
    Тхт="СБК_СодержаниеДрагметалловВНоменкре.ПередЗаписью() /Подразделение="+ё.Подразделение+"/Номнклатура="+ё.Номенклатура+"/Драгметалл="+ё.Драгметалл+"/ПартияДМ="+ё.ПартияДМ+"/Склад="+ё.Склад+"/Сотрудник="+ё.Сотрудник+"//Остаток="+ё.Остаток;
    Сообщить(Тхт);
    Отказ=Истина;
    КонецЕсли;

    КонецЦикла;

    КонецЕсли; //ЭтотОбъект.Количество()=0

    КонецЕсли; //Константы.КонтрольИсточниковФинансирования.Получить()
    КонецПроцедуры

    Процедура ПриЗаписи(Отказ, Замещение) //00 Бобейко 25.05.2017
    Если Константы.КонтрольИсточниковФинансирования.Получить() Тогда
    //Проверим Остатки
    ТЗ = ЭтотОбъект.Выгрузить();
    ТЗ.Свернуть("Период,ВидДвижения,Организация,Подразделение,Номенклатура,Драгметалл,ПартияДМ,Склад,Сотрудник","Количество");

    Для Каждого ё из ТЗ Цикл
    Если ё.ВидДвижения=ВидДвиженияНакопления.Расход Тогда
    ё.Количество=-ё.Количество;
    КонецЕсли;
    КонецЦикла;
    Запрос=Новый Запрос;
    Запрос.Текст="ВЫБРАТЬ
    | ТЗ.Организация,
    | ТЗ.Подразделение,
    | ТЗ.Номенклатура,
    | ТЗ.Драгметалл,
    | ТЗ.ПартияДМ,
    | ТЗ.Склад,
    | ТЗ.Сотрудник,
    | ТЗ.Количество
    |ПОМЕСТИТЬ Движения
    |ИЗ
    | &ТЗ КАК ТЗ
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |ЕСТЬNULL(СБК_СодержаниеДрагметалловВНоменклатуреОстатки.КоличествоОстаток, 0) + Движения.Количество КАК Остаток,
    | Движения.Организация,
    | Движения.Подразделение,
    | Движения.Номенклатура,
    | Движения.Драгметалл,
    | Движения.ПартияДМ,
    | Движения.Склад,
    | Движения.Сотрудник
    |ИЗ
    | Движения КАК Движения
    | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СБК_СодержаниеДрагметалловВНоменклатуре.Остатки(&Dat, ) КАК СБК_СодержаниеДрагметалловВНоменклатуреОстатки
    | ПО Движения.Организация = СБК_СодержаниеДрагметалловВНоменклатуреОстатки.Организация
    | И Движения.Подразделение = СБК_СодержаниеДрагметалловВНоменклатуреОстатки.Подразделение
    | И Движения.Номенклатура = СБК_СодержаниеДрагметалловВНоменклатуреОстатки.Номенклатура
    | И Движения.Драгметалл = СБК_СодержаниеДрагметалловВНоменклатуреОстатки.Драгметалл
    | И Движения.ПартияДМ = СБК_СодержаниеДрагметалловВНоменклатуреОстатки.ПартияДМ
    | И Движения.Склад = СБК_СодержаниеДрагметалловВНоменклатуреОстатки.Склад
    | И Движения.Сотрудник = СБК_СодержаниеДрагметалловВНоменклатуреОстатки.Сотрудник
    |
    |УПОРЯДОЧИТЬ ПО
    | Остаток";

    Запрос.УстановитьПараметр("ТЗ",ТЗ);
    Запрос.УстановитьПараметр("Dat",ЭтотОбъект.Отбор.регистратор.Значение.Дата);
    ё=Запрос.Выполнить().Выбрать();
    Пока ё.Следующий() Цикл //Проверяем остатки на дату документа
    если ё.Остаток<0 Тогда
    Тхт="СБК_СодержаниеДрагметалловВНоменкре.ПриЗаписи() /Подразделение="+ё.Подразделение+"/Номнклатура="+ё.Номенклатура+"/Драгметалл="+ё.Драгметалл+"/ПартияДМ="+ё.ПартияДМ+"/Склад="+ё.Склад+"/Сотрудник="+ё.Сотрудник+"//Остаток="+ё.Остаток;
    Сообщить(Тхт);
    Отказ=Истина;
    КонецЕсли;

    КонецЦикла;

    КонецЕсли
    КонецПроцедуры

    В этом случае во всех документах работающих с регистром (а их 12 штук) можно ничего не писать, ибо регистр сам следит за своими остатками.
    Есть правда недостатки например
    // 1Документ 15.05.2017 Приход 15 шт Х
    // 2Документ 20.05.2017 Списание 8 шт Х
    // 3Документ 27.25.2017 Приход 20 шт Х
    То теперь можно отменить проведение 1Документа

    Но подобные недостатки встречаются во всех методиках, более того все методики (за исключением моей) рассчитаны только на оперативное проведение документов (чего не встречал в природе!?)

  24. Александр

    При параллельном проведении документа получаю ошибку:

    по причине:
    Ошибка выполнения запроса
    по причине:
    Конфликт блокировок при выполнении транзакции:
    Microsoft SQL Server Native Client 11.0: Превышено время ожидания запроса на блокировку.
    HRESULT=80040E31, SQLSrvr: SQLSTATE=HYT00, state=33, Severity=10, native=1222, line=1

    В запросе выбираются документы проводимого типа.
    При проведении документа блокируется вся таблица документа? И ее нельзя прочитать в соседней транзакции?

    • Евгений Гилев (Мастер-тренер)

      Совершенно непонятно о какой конфигурации и каких документах идет речь.
      Как выполняется блокировка, какие комбинации измерений блокируются, есть ли пересечения в блокируемых изменениях в Ваших документах – это те вопросы, на которые Вы должны ответить, чтобы понять источник проблемы.

      А ведь есть еще режим блокировок – автоматический или управляемый.

      При проведении документа блокируется вся таблица документа?

      Нет, не блокируется.

      • Александр

        Конфигурация нетиповая. Как воспроизводится. В процедуре ОбработкаПроведения есть сокращенно такой запрос “Выбрать Документы.Ссылка из Документы.РегистрацияПотребленияУслугПоОбъектамПотреблениеУслугПоОбъектам Как документы”. Провожу документ1, в процедуре ОбработкаПроведения ставлю точку останова. В соседней сессии провожу другой документ, и ошибка выходит на выполнении этого запроса, из чего предположил что блокируется таблица документов. Что интересно, открываю 3 сессию и там выполняю этото запрос в консоли, он выполняется.

        • Евгений Гилев (Мастер-тренер)

          Что-то конкретное по Вашей ситуации подсказать не удастся – мало данных.
          Рекомендую пройти курс по Ускорению и Оптимизации 1С, чтобы самостоятельно решить проблему: http://курсы-по-1с.рф/1c-v8/optimization/

          Документы должны проводится параллельно, если у в них нет пересекающихся блокируемых наборов данных.

          P.S.

          Имя документ “РегистрацияПотребленияУслугПоОбъектамПотреблениеУслугПоОбъектам” тянет на рекорд :)

  25. Никита

    Можно ли в старой методике не очищать предварительно движения, а получать данные об остатках на момент времени с видом границы “исключая”?

    • Евгений Гилев (Мастер-тренер)

      Нет, это не спасет.
      Проблема будет, когда дата документа сдвинута вперед.
      Например, документ проведен в 9:00:00, через час в этот документ возвращается и меняют время на 10:00:00 (или просто перепроводят оперативно).

      • Артур

        Правильно ли я понимаю, что платформа при оперативном проведении, несмотря на явное указание в установке параметров запроса границы на которую ей необходимо читать остатки, в целях оптимизации прочитает их на 31.12.3999, иными словами обратится напрямую к таблице итогов без соединения последней с таблицей движения.
        Таким образом, во избежание излишних блокировок при записи следует анализировать режим проведения и в случае его оперативности записывать пустой набор записей перед чтением остатков.
        Пример кода:
        Запрос.УстановитьПараметр(“МоментВремени”,МоментВремени());
        Если Режим = РежимПроведенияДокумента.Оперативный Тогда
        Движения.СтоимостьНоменклатуры.Записать();
        КонецЕсли;

        Ну и сразу вытекающий запрос, а где же работает такая подмена
        воли и как давно?

        Раньше насколько я понимаю было актуально писать следующее:
        МоментВремени = ?(Режим = РежимПроведенияДокумента.Оперативный, Неопределено, МоментВремени());
        Запрос.УстановитьПараметр(“МоментВремени”,МоментВремени());

        • Вячеслав Вязигин

          День добрый!

          Вы неправильно понимаете. Платформа оперирует текстом запроса, который написал разработчик, независимо от оперативности проведения документа. Год 3999 подставляется в параметр запроса автоматически только в том случае, когда запрос не имеет параметра даты на условие виртуальной таблицы остатков.

          Записывать пустой набор записей или нет зависит от методики проведения (старая или новая) документа. Не ищите никаких скрытых смыслов и «подмены воли», на все воля разработчика :)

  26. ShootNICK

    Запрос.Текст =
    “ВЫБРАТЬ
    | Остатки.Номенклатура КАК Номенклатура,
    | -Остатки.КоличествоОстаток КАК Дефецит

    дефИцит, извините )

  27. nvv1970

    Автор немного слукавил, что для старой методики запись пустых наборов обязательна )) В простом случае(как в примере) можно обойтись и без этого.
    Но абсолютно верно что при сдвиге даты документа, при несоответствии периода записей и даты документа при проведении для старой методики очистка нужна, а для новой – нет.

    • Евгений Гилев (Мастер-тренер)

      Статья для начинающих, поэтому усложнять её не планировали.
      А частные случаи, анализ сдвига даты документа мы рассматриваем в курсах :)

  28. Яков

    Всегда было интересно, зачем данные табличной части конкретного документа получать отдельным запросом, если они уже есть в прочитанном объекте. Ну вот не понимаю. Документ-объект уже в кэше, идёт объектная блокировка, нафига ещё таблицу БД дёргать? В сеансовые данные вывалили, таблицей значений дубли скрутили, параметром в другие запросы сунули. Где я неправ?

    • Евгений Гилев (Мастер-тренер)

      Можно пойти предложенным путем.

      Но какого-либо заметного ускорения Вы не получите.

      И вот почему. Вам всё равно ведь придется дергать СУБД чтобы создать временную таблицу.
      Да не надо будет обращаться к табличной части документа, но это обращение выполняется с условием по ссылке, а по ней всегда есть индекс – это условие отрабатывает очень быстро.

      • Яков

        Понял.
        В ряде случаев можно и без временной таблицы обойтись. Если я задам условие на вхождение в список, и его передам как параметр в запрос, это ведь не временная. А учитывая нынешнюю архитектуру, когда, например, “Номенклатура+Характеристика+Серия” = “Аналитика”, сделаю отбор по Аналитика В (&СписокИзТабЧасти) и всё.

        • Евгений Гилев (Мастер-тренер)

          Да, в ряде случаев можно обойтись без временной таблицы.

  29. topasha

    Спасибо за статью, очень интересно!
    Попробовал на живых людях ;)
    В самописной конфе есть подходящий регистр (два измерения, один ресурс). Использовался “старый” способ контроля остатков. Работало вполне сносно. Попробовал на нём “новый” способ контроля остатков, переписал обработку проведения. Чисто субъективно, по скорости работы никакой разницы не заметил. Регистр остатков используется интенсивно, работает более 60 пользователей одновременно. Только строк кода добавилось. Стоило ли заморачиваться с апгрейдом?

    • Евгений Гилев (Мастер-тренер)

      Реальное применение знаний – это всегда правильно.

      Разницу при собственном тестировании одним пользователем Вы вряд ли заметите.
      Даже, если запускаете клиент-серверный вариант.

      Поэтому имеет смысл еще раз проверить алгоритм и запустить в продакшн – посмотреть результат. Если сильно заморочиться, можно и сравнить производительность обоих способов :)
      Но вполне возможно результат будет виден на глаз, если при старом способе когда-нибудь возникли сложности, связанные с проведением этого документа.

      Можно пойти и другим путем – поставить 1С:ТестЦентр и сэмулировать интенсивную работу нескольких пользователей и оценить результаты :)

  30. Павел

    Всегда интересовало как реализовано ФИФО в рамках новых типовых. По старой методике? Ведь там нужно обращение у данным регистра

    • Евгений Гилев (Мастер-тренер)

      В 1С:Бухгалтерии – по старой методике.

      В УТ 11 – по новой.
      Фокус УТ 11 в том, что списание партий происходит НЕ в момент проведения выбытия товаров, а в момент закрытия месяца.

      • Яков

        Это как? Тогда получается, что данные партионного учёта неактуальны вплоть до закрытия месяца? И нормальной себестоимости ожидать не приходится?

        • Евгений Гилев (Мастер-тренер)

          Закрытие месяца не обязательно выполнять 1 раз в месяц.
          Настраивается регламентное задание и выбирается требуемая периодичность – раз в день, каждый час или чаще.
          Конечно это создает определенную нагрузку на сервер, поэтому приемлемое значение выбирается по двум критериям – требуемая актуальность данных и допустимой нагрузки на кластер серверов.

  31. Nikolay

    Здравствуйте!
    Спасибо за статью!

    Зачем в первом варианте циклом обходится выборка, если посчитать дельту можно в запросе и выводить записи только с отрицательной дельтой?

    • Евгений Гилев (Мастер-тренер)

      Добрый день!

      Видимо речь о старой методики контроля остатков.
      Кроме контроля остатков в выборке мы производим формирование движений. Дельту можно было бы посчитать и в запросе, но принципиальных изменений это не даст.

      Если же Вы предлагаете создать еще один запрос, который возвращает ошибочные записи, то такой подход в общем случае будет хуже – из-за “накладных” расходов.

  32. Четверг

    1) В новых конфигурациях (Управляемый интерфейс) Это нужно делать:
    Движения.СвободныеОстатки.Очистить(); ? или достаточно будет:
    Движения.СвободныеОстатки.Записать();
    2) При подготовке к экзамену на спеца в основном все пишут один раз: Движения.СвободныеОстатки.Записывать = Истина; , т.е. Сначала очищают Движения.Записать(), затем в конце пишут Записывать = Истина.
    У вас Движения.СвободныеОстатки.Записывать = Истина(); вначале и в конце. Для чего нужен код который вначале?

    • Четверг

      3) ?(Режим = РежимПроведенияДокумента.Оперативный,
      Неопределено,…). Это вроде бы тоже на экзаменах не пишут, а передают либо Момент либо Границу. Не уверен. Вроде как советы от экзаменаторов. Могу ошибаться.

      • Евгений Гилев (Мастер-тренер)

        Даже, если это на экзамене не обязательно – в реальной жизни это желательное действие.
        Поскольку в этом случае остатки для оперативно проводимых документов будут получаться максимально быстро.

    • Евгений Гилев (Мастер-тренер)

      1. Это желательно делать.
      Набор записей может быть предварительно прочитан. Например, в событии ПередЗаписью или на форме документа.
      2. Метод Движения.Записать() записывает только те наборы записей, у которых свойство Записывать равно Истина.
      Более того, после записи этот метод сбрасывает свойство Записывать в Ложь.
      Поэтому свойство это нужно устанавливать дважды, если речь идет о старой методике контроля остатков.

      • Елена

        Готовлюсь к экзамену на специалиста по платформе. В задачах с использованием старой методики ставлю Записывать = Истина один раз (в начале при очистке движений), флаг не сбрасывается – можно в отладчике увидеть и движения документа записываются в регистр по окончании транзакции проведения. Не будет ли использование Записывать = Истина второй раз в конце ошибкой на экзамене?

        • Евгений Гилев (Мастер-тренер)

          А каким образом Вы выполняете запись в регистр?

          Если через Движения.ИмяРегистра.Записать(), то флаг не будет сбрасываться.
          А правильно записывать так – Движения.Записать().

          • Четверг

            почему править так – Движения.Записать()? Почему не рекомендуете очищать таким образом – Движения.ИмяРегистра.Записать(), а записывать Движения.ИмяРегистра.Записывать = Истина;?

            • Четверг

              почему это хуже?:
              -Движения.ИмяРегистра.Очистить();
              -Движения.ИмяРегистра.Записать();
              -Движения.ИмяРегистра.Записывать = Истина;

            • Евгений Гилев (Мастер-тренер)

              Потому что при использовании записи не через Движения.Записать() есть опасность взаимоблокировки.
              Посмотрите описание области кода “1. Очистка старых движений регистра” в этой статье.

              Кроме того, предлагаемые Вами метод может быть признан ошибкой на экзамене (со снижением оценки).

              • Четверг

                Я думал что при записи пустого набора блокировка не накладывается на регистр.
                При записи пустого регистра (удаления старых движений) будет накладываться блокировка? Если мы очищаем движения по измерениям Товар1 и Товар2, то автоматически будет накладываться блокировка на регистр по измерениям Товар1 и Товар2?

                • Евгений Гилев (Мастер-тренер)

                  Да, всё верно, блокировка при удалении движений накладывается автоматически по тем значениям измерений, которые удаляются.

                  А если быть более точным, то накладываются две блокировки – исключительная управляемая блокировка (в кластере серверов 1С) и X блокировка СУБД.

              • Asta0000

                “Потому что при использовании записи не через Движения.Записать() есть опасность взаимоблокировки.” Источник: ©Курсы-по-1С.рф

                Т.е. если использовать Движения.Записать() взаимоблокировки не будет? Например в таком коде:
                Первый документ
                Движения.СвободныеОстатки.Записывать = Истина;
                Движения.Записать();

                Движения.Себестоимость.Записывать = Истина;
                Движения.Записать();

                Второй документ Движения.Себестоимость.Записывать = Истина;
                Движения.Записать();

                Движения.СвободныеОстатки.Записывать = Истина;
                Движения.Записать();

                Если не будет – то почему, а если будет, то надо либо подробнее об этом либо не упоминать

  33. polax

    Спасибо за статью. Возник технический вопрос. А если дата документа смещается не вперед, а назад? Очистка регистра не нужна?

    • Евгений Гилев (Мастер-тренер)

      Не нужна, поскольку будущие движения не повлияют на прошлые остатки.

  34. Василий

    Вопрос снимаю, так как блокировки рассматриваются в следующей статье. Но, думаю, надо сказать это.

    • Евгений Гилев (Мастер-тренер)

      Вроде как об этом сказано в специальном разделе “Но это ещё не все!”.

  35. Сергей

    Есть вопрос по старой методике проведения. Зачем чистить движения документа раз это такая тяжелая операция? Что нам мешает в запросе остатков получить движения нашего документа и вычесть их из остатков, проверив период движений. Добавится одна выборка из регистра с отбором по регистратору (очень быстрая операция, регистратор индексирован), одно соединение/объединение с остатками(обычно строк документа гораздо меньше чем записей в регистре и соединить таблицы это легкая операция)

    • Евгений Гилев (Мастер-тренер)

      Да, мы это уже обсуждали в комментариях ниже.
      Такой способ приемлем и хорошо подойдет для простых случаев (которые, например, рассмотрены в статье).
      Но в сложных случаях, когда нужно учитывать партии и еще несколько аналитик – возникают нюансы в запросах, они будут не такими простыми как кажется.

  36. gosn1ck

    Добрый день.
    спасибо за статью!
    слишком строгая получилось фраза “Поэтому единственный правильный вариант – использовать вид границы «Включая»”, ведь момент времени можно и не указывать вовсе.
    на одном из чудных проектов пришлось делать вообще 2 проверки и на момент времени и без момента … всё как всегда зависит от задачи

    • Евгений Гилев (Мастер-тренер)

      Добрый день!

      Здесь мы подстраиваемся под требования Аттестации и считаем, что остатки нужно контролировать на момент проведения документа.

      А на проектах ситуации бывают действительно разные :)

  37. Alex_grem

    Т.е. в УТ 11 контроль остатков идет по регистру “Свободные остатки” новой методикой или по регистру “Себестоимость товаров” тоже идет контроль?

  38. kalamber

    Добрый день! Статья очень полезная, однако при применении новой методики также идет обращение к регистру контроля остатка для получения отрицательных остатков

    Критерий применимости — если для формирования движений нет необходимости обращаться к данным контролируемого регистра Источник: ©Курсы-по-1С.рф

    Или имеется ввиду отсутствие левого соединения?

    • Евгений Гилев (Мастер-тренер)

      Добрый день!

      Цитата:

      Критерий применимости — если для формирования движений нет необходимости обращаться к данным контролируемого регистра.

      Ключевой момент выделил жирным.

      В новой методике прежде, чем сформировать движения по регистру “Свободные остатки” нет необходимости обращаться к этому регистру.

  39. Василий

    В “Сообщение.Текст = “Товара “+ВыборкаТовары.Номенклатура+” недос”
    вы выводите ссылку, а это неправильно. Получается запрос в цыкле. Надо использовать представление. Или я ошибаюсь?

    • Евгений Гилев (Мастер-тренер)

      С одной стороны – да, это неплохо.
      С другой стороны, Вы удивитесь, но в типовой УТ 11/ERP/КА выводимая в сообщении об ошибке номенклатура получается так – СокрЛП(Выборка.Номенклатура), где Выборка.Номенклатура – это ссылка.

      Но, чтобы никого не смущало, добавим в запрос получение представления.

      • Алексей

        Так это же очевидно быстрее – не формировать представление в запросе, а выводить только если произошла ошибка, генерируя представление в этом месте. Ошибка ведь далеко не всегда происходит, и мы сэкономим на запросах.

    • palsergeich

      Получение основного представления на сервере ничтожная по затратам операция, ибо у ссылочных типов отдельный индекс на это, ибо даже на высоконагруженной базе при выводе нескольких сотен тысяч представлений по ссылке в ТабДок, сколько нибудь криминального замедления замечено не было, при сравнении с выводом сразу представления. А уж тем более в диагностике контроля остатков, где возникновение такой ситуации считается маловероятным событием, тратить время на то что бы вспомнить, как называется это поле в запросе – не оправдано что ли, да и более того, основное представление может не входить в используемый индекс и привести к key lookup или скану.
      Конкретно в этом примере для того что бы вычислить ПРЕДСТАВЛЕНИЕССЫЛКИ, будет соединение с таблицей номенклатуры, потому что ссылка на номенклатуру, ничего не знает о представлении, оно хранится в своей таблице.
      Это скорее как рекомендация всегда индексировать поля соединения временных таблиц, сколько не тестировал – лучший результат – совпадение по времени с отсутствием индексирования, в остальных случаях – увеличение времени работы запроса. Все рекомендации которые дает 1с – это общая практика, но не всегда это правильно.

      Текст запроса в профайлере без представления
      exec sp_executesql N’SELECT
      T1.Fld58RRef,
      T1.Fld59Balance_
      FROM (SELECT
      T2._Fld58RRef AS Fld58RRef,
      T2._Fld59 AS Fld59Balance_
      FROM dbo._AccumRgT60 T2 WITH(NOLOCK)
      WHERE T2._Period = @P1 AND (T2._Fld59 @P2) AND (T2._Fld59 @P3)) T1′,N’@P1 datetime2(3),@P2 numeric(10),@P3 numeric(10)’,’5999-11-01 00:00:00′,0,0

      Текст запроса в профайлере с представлением
      exec sp_executesql N’SELECT
      T1.Fld58RRef,
      T1.Fld58RRef,
      T3._Description,
      T1.Fld59Balance_
      FROM (SELECT
      T2._Fld58RRef AS Fld58RRef,
      T2._Fld59 AS Fld59Balance_
      FROM dbo._AccumRgT60 T2 WITH(NOLOCK)
      WHERE T2._Period = @P1 AND (T2._Fld59 @P2) AND (T2._Fld59 @P3)) T1
      LEFT OUTER JOIN dbo._Reference12 T3 WITH(NOLOCK)
      ON T1.Fld58RRef = T3._IDRRef’,N’@P1 datetime2(3),@P2 numeric(10),@P3 numeric(10)’,’5999-11-01 00:00:00′,0,0

      Выводы делайте сами.

  40. Дмитрий

    Очень интересная и полезная статья,
    но

    //  7. Установка флага записи движений в конце транзакции
         
    Движения.СвободныеОстатки.Записывать = Истина;

    необходим только если у документа выбрано свойство
    Запись движений при проведении:Записывать выбранные.
    В случае если определено:Записывать модифицированные
    он не обязателен

    • Евгений Гилев (Мастер-тренер)

      Не хотелось перегружать статью деталями, учитывая, что:
      1. В типовых этот флаг у документов установлен в “Записывать выбранные”
      2. В новой ИБ по умолчанию у документов указывается свойство “Записывать выбранные”.

      • Дмитрий

        Солидарен с вами, но когда у меня принимали экзамен, товарищ экзаменатор плотно прошелся по этому вопросу.

        • Евгений Гилев (Мастер-тренер)

          Ок, добавил этот момент в качестве ремарки в статью, чтобы не перегружать основной контент.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Вход на сайт

Зарегистрироваться

Подтверждение регистрации будет отправлено на указанный e-mail.

Я подтверждаю, что ознакомлен(а) с Пользовательским соглашением, принимаю его условия и даю свое согласие на обработку моих персональных данных.

Восстановить доступ

E-mail или логин

Ссылка на создание нового пароля будет отправлена на указанный e-mail.